Introduction and Background

Wildfires are growing in both frequency and intensity. This worrying trend is largely linked to global warming, human activities that impact the environment, and natural ecological shifts. The significant damage caused by these events underscores the urgent need for reliable tools that can predict wildfire risk, allowing for better preparation and response.

This project investigates the application of predictive algorithms to forecast critical wildfire characteristics in California, specifically focusing on the duration of active burning (persistence) and the potential for fire expansion (spread risk). Utilizing a comprehensive dataset of historical wildfire incidents and relevant environmental variables, we developed and evaluated predictive models for these key wildfire attributes. The results of this project demonstrate the potential of offering valuable insights for proactive mitigation and resource allocation in this fire-prone region.

library(dplyr)
library(tidyr)
library(glmnet)
library(BART)
library(randomForest)
library(ggplot2)
library(readxl)
library(plotly)
library(ggcorrplot)
library(patchwork)
data <- read.csv("../Data/WildFire_DataSet.csv")
data |> head(5)
glimpse(data)
Rows: 1,132
Columns: 47
$ incident_id                      <chr> "2ca11d45-8139-4c16-8af0-880d99b21e82", "8f61f461-552d-4538-b186-35a…
$ incident_url                     <chr> "https://www.fire.ca.gov/incidents/2017/10/31/bridge-fire/", "https:…
$ incident_type                    <chr> "", "Wildfire", "", "", "", "", "", "", "", "", "", "", "", "", "", …
$ incident_name                    <chr> "bridge", "pala", "river", "gold", "panther", "silverado", "yellow",…
$ incident_date_created            <chr> "2017-10-31 11:22:00+00:00", "2009-05-24 14:56:00+00:00", "2013-02-2…
$ incident_date_extinguished       <chr> "2018-01-09 13:46:00+00:00", "2009-05-25 00:00:00+00:00", "2013-02-2…
$ incident_date_last_update        <chr> "2018-01-09T13:46:00Z", "2020-09-16T14:07:35Z", "2022-10-24T11:39:23…
$ incident_dateonly_extinguished   <chr> "1/9/18", "5/25/09", "2/28/13", "5/1/13", "5/9/13", "5/1/13", "5/3/1…
$ incident_dateonly_created        <chr> "10/31/17", "5/24/09", "2/24/13", "4/30/13", "5/1/13", "4/30/13", "5…
$ incident_is_final                <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y"…
$ is_active                        <chr> "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N", "N"…
$ incident_administrative_unit     <chr> " Shasta-Trinity National Forest ", "CAL FIRE San Diego Unit", "CAL …
$ incident_administrative_unit_url <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
$ incident_county                  <chr> "Shasta", "San Diego", "Inyo", "Madera", "Tehama", "Napa", "Sonoma",…
$ incident_location                <chr> "I-5 and Turntable Bay, 7 miles NE of Shasta Lake ", "Hwy 76 and Pal…
$ incident_longitude               <dbl> -122.3090, -117.2036, -118.0165, -119.6350, -121.5956, -122.3508, -1…
$ incident_latitude                <dbl> 40.77400, 33.68240, 36.60258, 37.11630, 40.19006, 38.44179, 38.63883…
$ incident_acres_burned            <int> 37, 122, 407, 274, 6896, 75, 125, 2956, 354, 217, 75, 650, 712, 35, …
$ incident_containment             <int> 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100…
$ incident_control                 <chr> "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", …
$ incident_cooperating_agencies    <chr> " Shasta-Trinity National Forest ", "CAL FIRE San Diego Unit", "CAL …
$ calfire_incident                 <chr> "False", "True", "True", "True", "True", "True", "True", "True", "Tr…
$ notification_desired             <chr> "False", "False", "False", "False", "False", "False", "False", "Fals…
$ Fire_Duration                    <int> 70, 0, 4, 0, 7, 0, 2, 3, 0, 3, 1, 1, 1, 0, 0, 0, 0, 0, 3, 0, 4, 3, 1…
$ log_acres_burned                 <dbl> 3.637586, 4.812184, 6.011267, 5.616771, 8.838842, 4.330733, 4.836282…
$ wind_temp                        <dbl> 95.49381, 351.41634, 22.53214, 140.00773, 114.24478, 345.69642, 194.…
$ elevation                        <dbl> 355, 441, 1116, 490, 1379, 63, 248, 2412, 27, 534, 620, 926, 374, 17…
$ landcover                        <dbl> 42, 22, 52, 71, 42, 22, 43, 42, 82, 52, 21, 71, 52, 71, 52, 71, 52, …
$ aspect                           <dbl> 74, 67, 23, 180, 186, 270, 306, 169, 121, 71, 141, 41, 268, 71, 25, …
$ slope                            <dbl> 39, 2, 3, 11, 11, 5, 18, 17, 5, 22, 4, 9, 29, 16, 18, 10, 8, 8, 7, 9…
$ uid                              <chr> "2ca11d45-8139-4c16-8af0-880d99b21e82bridge", "8f61f461-552d-4538-b1…
$ min_temp                         <dbl> -0.3, 26.0, -0.2, 12.3, 4.3, 14.3, 11.9, 3.8, 14.8, 11.0, 13.2, 8.6,…
$ max_temp                         <dbl> 25.2, 27.5, 15.2, 30.4, 26.5, 30.9, 32.8, 21.8, 35.3, 32.3, 36.0, 30…
$ avg_temp                         <dbl> 9.692782, 26.668750, 6.235833, 21.470833, 12.979630, 23.227083, 22.6…
$ avg_windspeed                    <dbl> 9.852054, 13.177083, 3.613333, 6.520833, 8.801852, 14.883333, 8.5833…
$ avg_precipitation                <dbl> 0.250058685, 0.220833333, 0.000000000, 0.000000000, 0.127777778, 0.0…
$ FIRE_NAME                        <chr> "bridge", "pala 4", "river", "gold", "panther", "silverado", "yellow…
$ ALARM_DATE                       <chr> "10/31/17", "5/24/09", "2/24/13", "4/30/13", "5/1/13", "4/30/13", "5…
$ GIS_ACRES                        <dbl> 35.51982, 106.11540, 406.84150, 183.64240, 6896.19800, 60.21228, 83.…
$ CAUSE                            <int> 2, 14, 14, 14, 9, 5, 11, 14, 2, 5, 2, 14, 3, 14, 9, 2, 7, 14, 18, 9,…
$ Year_Started                     <int> 2017, 2009, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 2013, 20…
$ ndvi                             <dbl> 0.871471471, NA, 0.088693297, 0.021794222, 0.136799303, 0.283749363,…
$ avg_pdsi                         <dbl> 2.7200000, NA, -2.0800000, -0.8916667, 1.0033333, 1.8200000, 1.73000…
$ avg_spi30d                       <dbl> 0.951666658, NA, -0.218333333, -0.224999999, -0.231666664, -0.249999…
$ fuel_type                        <chr> "Forest", "", "Shrubland", "Grassland", "Forest", "Urban", "Forest",…
$ cause_description                <chr> "Equipment/vehicles", "Unknown (Human)", "Unknown (Human)", "Unknown…
$ ndmi                             <dbl> 0.2141261995, 0.0059500197, -0.0380486585, 0.0489031225, 0.109610758…

Data Cleaning

library(naniar)
gg_miss_var(data) + labs(title = "Missing Data by Variable", y="Missing Counts")

head(data)
#Extracting Total Fire Duration 
year_fire <- data %>%
  group_by(Year_Started) %>%
  summarise(Total_Fire_Duration = sum(Fire_Duration, na.rm = TRUE), num_fire = n()) %>%
  mutate(avg_fire_dur = Total_Fire_Duration/num_fire) |> 
  dplyr::ungroup()

year_fire |> head(15)

Exploratory Data Analysis

# Create each plot
p1 <- ggplot(data, aes(x = Year_Started)) +
  geom_bar(fill = "firebrick") +
  theme_linedraw() +
  labs(title = "Number of Fires per Year", x = "Year", y = "Count")
  

p2 <- ggplot(year_fire, aes(x = as.factor(Year_Started), y = avg_fire_dur)) +
  geom_bar(stat = "identity", fill = "red") +
  labs(
    title = "Fire Duration According to the Year",
    x = "Year",
    y = "Fire Duration in Days"
  ) +
  scale_x_discrete(limits = as.character(2013:2023)) +
  theme_linedraw() +
  theme(plot.title = element_text(hjust = 0.5))

# Combine them side by side
p1 + p2

The bar charts displays the frequency and the total fire duration (in days) per year from 2013 to 2022. It highlights a dramatic spike in fire duration during 2017 and 2018, indicating those years experienced significantly longer wildfire events compared to other years in the dataset.

# Compute average acres burned per fuel type
fuel_stats <- data %>%
  group_by(fuel_type) %>%
  summarise(avg_acres_burned = mean(incident_acres_burned, na.rm = TRUE)) %>%
  arrange(desc(avg_acres_burned))

# Plot
ggplot(fuel_stats, aes(x = reorder(fuel_type, -avg_acres_burned), y = avg_acres_burned)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  theme_linedraw() +
  labs(title = "Average Acres Burned by Fuel Type",
       x = "Fuel Type", y = "Average Acres Burned") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

This bar chart displays the average acres burned by different fuel types. Forests have the highest average area burned, followed by shrubland and grassland. Non-burnable and barren areas show minimal fire impact.

data_new = data
data_new %>%
  count(fuel_type, sort = TRUE) %>%
  ggplot(aes(x = reorder(fuel_type, -n), y = n)) +
  geom_bar(stat = "identity", fill = "forestgreen") +
  labs(title = "Number of Incidents by Fuel Type", x = "Fuel Type", y = "Count") +
  theme_linedraw() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

This bar chart illustrates the number of fire incidents by fuel type. Urban, shrubland, and grassland areas report the highest incident counts. Despite forests having fewer incidents, they tend to result in larger burned areas compared to other types.

Geographical Scatter Plot

The map below displays the geographic distribution of wildfire ignition points across California, marked by red dots. It shows a high concentration of wildfire starts, highlighting areas most prone to fire activity.

df_train <- data %>%
  mutate(scaled_size = pmin(sqrt(incident_acres_burned) * 0.2))  # Cap at 15

# Create scatter map with better visibility
fig_location <- plot_ly(
  data = data,
  type = "scattermapbox",
  lon = ~incident_longitude,
  lat = ~incident_latitude,
  text = ~paste("Acres Burned:", incident_acres_burned),
  marker = list(color = "red"),
  mode = "markers"
) %>%
  layout(
    title = "Fire Locations",
    mapbox = list(
      style = "carto-positron",
      zoom = 5,  # Adjust zoom level
      center = list(
        lon = mean(data$incident_longitude, na.rm = TRUE),
        lat = mean(data$incident_latitude, na.rm = TRUE)
      )
    )
  )

# Show the plot
fig_location

Wildfire Analysis by Weather Factors

# Create individual scatter plots
p1 <- ggplot(data, aes(x = avg_windspeed, y = incident_acres_burned)) +geom_point(color = "blue") +theme_grey()

p2 <- ggplot(data, aes(x = avg_temp, y = incident_acres_burned)) +geom_point(color = "red") +theme_grey()

p3 <- ggplot(data, aes(x = avg_precipitation, y = incident_acres_burned)) +geom_point(color = "green4") +theme_grey()
# Arrange plots in a row with consistent sizing and shared Y axis
fig <- subplot(p1, p2, p3, nrows = 1, shareY = TRUE, titleX = TRUE, titleY = TRUE, widths = c(0.33, 0.33, 0.33)) %>%
  layout(
    title = list(
      text = "Wildfire Analysis by Weather Factors",  
      x = 0.5,    
      xanchor = "center",
      font = list(size = 20)  
    ),
    showlegend = TRUE,
    margin = list(l = 50, r = 50, b = 100, t = 100),
    xaxis = list(title = "Avg Wind Speed", zeroline = FALSE),
    xaxis2 = list(title = "Avg Temperature", zeroline = FALSE),
    xaxis3 = list(title = "Avg Precipitation", zeroline = FALSE),
    yaxis = list(title = "Acres Burned")
  )

fig

Correlation Heat Map

The heatmap illustrates the correlation between various features related to wildfire behavior and environmental conditions. Notably, minimum temperature shows a strong positive correlation with maximum temperature (0.84) and a strong negative correlation with fire duration (-0.78).

# Select specific columns from df2
df_cor <- data %>%
  select(Fire_Duration, incident_acres_burned, min_temp, max_temp, avg_temp, avg_windspeed,
         avg_precipitation, elevation,aspect, slope, ndvi, avg_pdsi, avg_spi30d, ndmi)

# Compute correlation matrix
cor_matrix <- cor(df_cor, use = "complete.obs")

# Plot correlation heatmap
ggcorrplot(cor_matrix, 
           method = "square", 
           type = "lower", 
           lab = TRUE, 
           lab_size = 5, 
           colors = c("blue", "white", "red"),
           title = "Feature Correlation Heatmap") +
  theme_linedraw()+
  theme(
    axis.text.x = element_text(face = "bold", size = 12, angle = 90),
    axis.text.y = element_text(face = "bold", size = 12),
    plot.title = element_text(face = "bold", size = 20, hjust = 0.5)
  )

LS0tCnRpdGxlOiAiRGF0YSBNaW5pbmcgUHJvamVjdCIKc3VidGl0bGU6ICJDYWxpZm9ybmlhIFdpbGRmaXJlIFByZWRpY3Rpb24iCmF1dGhvcjogIlNocnV0aSBFbGFuZ292YW4sIEFudXJhZyBNYWxsaWssIERpa3NoYSBQaHVsb3JpYSIKZGF0ZTogIjA0LzA3LzIwMjUiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogRmFsc2UKLS0tCgojIEludHJvZHVjdGlvbiBhbmQgQmFja2dyb3VuZAo+IFdpbGRmaXJlcyBhcmUgZ3Jvd2luZyBpbiBib3RoIGZyZXF1ZW5jeSBhbmQgaW50ZW5zaXR5LiBUaGlzIHdvcnJ5aW5nIHRyZW5kIGlzIGxhcmdlbHkgbGlua2VkIHRvIGdsb2JhbCB3YXJtaW5nLCBodW1hbiBhY3Rpdml0aWVzIHRoYXQgaW1wYWN0IHRoZSBlbnZpcm9ubWVudCwgYW5kIG5hdHVyYWwgZWNvbG9naWNhbCBzaGlmdHMuIFRoZSBzaWduaWZpY2FudCBkYW1hZ2UgY2F1c2VkIGJ5IHRoZXNlIGV2ZW50cyB1bmRlcnNjb3JlcyB0aGUgdXJnZW50IG5lZWQgZm9yIHJlbGlhYmxlIHRvb2xzIHRoYXQgY2FuIHByZWRpY3Qgd2lsZGZpcmUgcmlzaywgYWxsb3dpbmcgZm9yIGJldHRlciBwcmVwYXJhdGlvbiBhbmQgcmVzcG9uc2UuCj4KPiBUaGlzIHByb2plY3QgaW52ZXN0aWdhdGVzIHRoZSBhcHBsaWNhdGlvbiBvZiBwcmVkaWN0aXZlIGFsZ29yaXRobXMgdG8gZm9yZWNhc3QgY3JpdGljYWwgd2lsZGZpcmUgY2hhcmFjdGVyaXN0aWNzIGluIENhbGlmb3JuaWEsIHNwZWNpZmljYWxseSBmb2N1c2luZyBvbiB0aGUgZHVyYXRpb24gb2YgYWN0aXZlIGJ1cm5pbmcgKHBlcnNpc3RlbmNlKSBhbmQgdGhlIHBvdGVudGlhbCBmb3IgZmlyZSBleHBhbnNpb24gKHNwcmVhZCByaXNrKS4gVXRpbGl6aW5nIGEgY29tcHJlaGVuc2l2ZSBkYXRhc2V0IG9mIGhpc3RvcmljYWwgd2lsZGZpcmUgaW5jaWRlbnRzIGFuZCByZWxldmFudCBlbnZpcm9ubWVudGFsIHZhcmlhYmxlcywgd2UgZGV2ZWxvcGVkIGFuZCBldmFsdWF0ZWQgcHJlZGljdGl2ZSBtb2RlbHMgZm9yIHRoZXNlIGtleSB3aWxkZmlyZSBhdHRyaWJ1dGVzLiBUaGUgcmVzdWx0cyBvZiB0aGlzIHByb2plY3QgZGVtb25zdHJhdGUgdGhlIHBvdGVudGlhbCBvZiBvZmZlcmluZyB2YWx1YWJsZSBpbnNpZ2h0cyBmb3IgcHJvYWN0aXZlIG1pdGlnYXRpb24gYW5kIHJlc291cmNlIGFsbG9jYXRpb24gaW4gdGhpcyBmaXJlLXByb25lIHJlZ2lvbi4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdsbW5ldCkKbGlicmFyeShCQVJUKQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHJlYWR4bCkKbGlicmFyeShwbG90bHkpCmxpYnJhcnkoZ2djb3JycGxvdCkKbGlicmFyeShwYXRjaHdvcmspCmBgYAoKYGBge3J9CmRhdGEgPC0gcmVhZC5jc3YoIi4uL0RhdGEvV2lsZEZpcmVfRGF0YVNldC5jc3YiKQpgYGAKCmBgYHtyfQpkYXRhIHw+IGhlYWQoNSkKYGBgCgpgYGB7cn0KZ2xpbXBzZShkYXRhKQpgYGAKCiMjIERhdGEgQ2xlYW5pbmcgCgpgYGB7ciwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTh9CmxpYnJhcnkobmFuaWFyKQpnZ19taXNzX3ZhcihkYXRhKSArIGxhYnModGl0bGUgPSAiTWlzc2luZyBEYXRhIGJ5IFZhcmlhYmxlIiwgeT0iTWlzc2luZyBDb3VudHMiKQpgYGAKCmBgYHtyfQpoZWFkKGRhdGEpCmBgYAoKYGBge3J9CiNFeHRyYWN0aW5nIFRvdGFsIEZpcmUgRHVyYXRpb24gCnllYXJfZmlyZSA8LSBkYXRhICU+JQogIGdyb3VwX2J5KFllYXJfU3RhcnRlZCkgJT4lCiAgc3VtbWFyaXNlKFRvdGFsX0ZpcmVfRHVyYXRpb24gPSBzdW0oRmlyZV9EdXJhdGlvbiwgbmEucm0gPSBUUlVFKSwgbnVtX2ZpcmUgPSBuKCkpICU+JQogIG11dGF0ZShhdmdfZmlyZV9kdXIgPSBUb3RhbF9GaXJlX0R1cmF0aW9uL251bV9maXJlKSB8PiAKICBkcGx5cjo6dW5ncm91cCgpCgp5ZWFyX2ZpcmUgfD4gaGVhZCgxNSkKYGBgCgojIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzCgpgYGB7ciwgZmlnLndpZHRoPTEwLCB3YXJuaW5nPUZBTFNFfQojIENyZWF0ZSBlYWNoIHBsb3QKcDEgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gWWVhcl9TdGFydGVkKSkgKwogIGdlb21fYmFyKGZpbGwgPSAiZmlyZWJyaWNrIikgKwogIHRoZW1lX2xpbmVkcmF3KCkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIEZpcmVzIHBlciBZZWFyIiwgeCA9ICJZZWFyIiwgeSA9ICJDb3VudCIpCiAgCgpwMiA8LSBnZ3Bsb3QoeWVhcl9maXJlLCBhZXMoeCA9IGFzLmZhY3RvcihZZWFyX1N0YXJ0ZWQpLCB5ID0gYXZnX2ZpcmVfZHVyKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInJlZCIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiRmlyZSBEdXJhdGlvbiBBY2NvcmRpbmcgdG8gdGhlIFllYXIiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiRmlyZSBEdXJhdGlvbiBpbiBEYXlzIgogICkgKwogIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYXMuY2hhcmFjdGVyKDIwMTM6MjAyMykpICsKICB0aGVtZV9saW5lZHJhdygpICsKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKCiMgQ29tYmluZSB0aGVtIHNpZGUgYnkgc2lkZQpwMSArIHAyCmBgYAoKPiBUaGUgYmFyIGNoYXJ0cyBkaXNwbGF5cyB0aGUgZnJlcXVlbmN5IGFuZCB0aGUgdG90YWwgZmlyZSBkdXJhdGlvbiAoaW4gZGF5cykgcGVyIHllYXIgZnJvbSAyMDEzIHRvIDIwMjIuIEl0IGhpZ2hsaWdodHMgYSBkcmFtYXRpYyBzcGlrZSBpbiBmaXJlIGR1cmF0aW9uIGR1cmluZyAyMDE3IGFuZCAyMDE4LCBpbmRpY2F0aW5nIHRob3NlIHllYXJzIGV4cGVyaWVuY2VkIHNpZ25pZmljYW50bHkgbG9uZ2VyIHdpbGRmaXJlIGV2ZW50cyBjb21wYXJlZCB0byBvdGhlciB5ZWFycyBpbiB0aGUgZGF0YXNldC4KCmBgYHtyfQojIENvbXB1dGUgYXZlcmFnZSBhY3JlcyBidXJuZWQgcGVyIGZ1ZWwgdHlwZQpmdWVsX3N0YXRzIDwtIGRhdGEgJT4lCiAgZ3JvdXBfYnkoZnVlbF90eXBlKSAlPiUKICBzdW1tYXJpc2UoYXZnX2FjcmVzX2J1cm5lZCA9IG1lYW4oaW5jaWRlbnRfYWNyZXNfYnVybmVkLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBhcnJhbmdlKGRlc2MoYXZnX2FjcmVzX2J1cm5lZCkpCgojIFBsb3QKZ2dwbG90KGZ1ZWxfc3RhdHMsIGFlcyh4ID0gcmVvcmRlcihmdWVsX3R5cGUsIC1hdmdfYWNyZXNfYnVybmVkKSwgeSA9IGF2Z19hY3Jlc19idXJuZWQpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic3RlZWxibHVlIikgKwogIHRoZW1lX2xpbmVkcmF3KCkgKwogIGxhYnModGl0bGUgPSAiQXZlcmFnZSBBY3JlcyBCdXJuZWQgYnkgRnVlbCBUeXBlIiwKICAgICAgIHggPSAiRnVlbCBUeXBlIiwgeSA9ICJBdmVyYWdlIEFjcmVzIEJ1cm5lZCIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQoKYGBgCgo+VGhpcyBiYXIgY2hhcnQgZGlzcGxheXMgdGhlIGF2ZXJhZ2UgYWNyZXMgYnVybmVkIGJ5IGRpZmZlcmVudCBmdWVsIHR5cGVzLiBGb3Jlc3RzIGhhdmUgdGhlIGhpZ2hlc3QgYXZlcmFnZSBhcmVhIGJ1cm5lZCwgZm9sbG93ZWQgYnkgc2hydWJsYW5kIGFuZCBncmFzc2xhbmQuIE5vbi1idXJuYWJsZSBhbmQgYmFycmVuIGFyZWFzIHNob3cgbWluaW1hbCBmaXJlIGltcGFjdC4KCgpgYGB7cn0KZGF0YV9uZXcgPSBkYXRhCmRhdGFfbmV3ICU+JQogIGNvdW50KGZ1ZWxfdHlwZSwgc29ydCA9IFRSVUUpICU+JQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoZnVlbF90eXBlLCAtbiksIHkgPSBuKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImZvcmVzdGdyZWVuIikgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIEluY2lkZW50cyBieSBGdWVsIFR5cGUiLCB4ID0gIkZ1ZWwgVHlwZSIsIHkgPSAiQ291bnQiKSArCiAgdGhlbWVfbGluZWRyYXcoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkKYGBgCj4gVGhpcyBiYXIgY2hhcnQgaWxsdXN0cmF0ZXMgdGhlIG51bWJlciBvZiBmaXJlIGluY2lkZW50cyBieSBmdWVsIHR5cGUuIFVyYmFuLCBzaHJ1YmxhbmQsIGFuZCBncmFzc2xhbmQgYXJlYXMgcmVwb3J0IHRoZSBoaWdoZXN0IGluY2lkZW50IGNvdW50cy4gRGVzcGl0ZSBmb3Jlc3RzIGhhdmluZyBmZXdlciBpbmNpZGVudHMsIHRoZXkgdGVuZCB0byByZXN1bHQgaW4gbGFyZ2VyIGJ1cm5lZCBhcmVhcyBjb21wYXJlZCB0byBvdGhlciB0eXBlcy4KCiMjIEdlb2dyYXBoaWNhbCBTY2F0dGVyIFBsb3QKCj4gVGhlIG1hcCBiZWxvdyBkaXNwbGF5cyB0aGUgZ2VvZ3JhcGhpYyBkaXN0cmlidXRpb24gb2Ygd2lsZGZpcmUgaWduaXRpb24gcG9pbnRzIGFjcm9zcyBDYWxpZm9ybmlhLCBtYXJrZWQgYnkgcmVkIGRvdHMuIEl0IHNob3dzIGEgaGlnaCBjb25jZW50cmF0aW9uIG9mIHdpbGRmaXJlIHN0YXJ0cywgaGlnaGxpZ2h0aW5nIGFyZWFzIG1vc3QgcHJvbmUgdG8gZmlyZSBhY3Rpdml0eS4KCmBgYHtyLGZpZy53aWR0aD0xMCwgd2FybmluZz1GQUxTRX0KZGZfdHJhaW4gPC0gZGF0YSAlPiUKICBtdXRhdGUoc2NhbGVkX3NpemUgPSBwbWluKHNxcnQoaW5jaWRlbnRfYWNyZXNfYnVybmVkKSAqIDAuMikpICAjIENhcCBhdCAxNQoKIyBDcmVhdGUgc2NhdHRlciBtYXAgd2l0aCBiZXR0ZXIgdmlzaWJpbGl0eQpmaWdfbG9jYXRpb24gPC0gcGxvdF9seSgKICBkYXRhID0gZGF0YSwKICB0eXBlID0gInNjYXR0ZXJtYXBib3giLAogIGxvbiA9IH5pbmNpZGVudF9sb25naXR1ZGUsCiAgbGF0ID0gfmluY2lkZW50X2xhdGl0dWRlLAogIHRleHQgPSB+cGFzdGUoIkFjcmVzIEJ1cm5lZDoiLCBpbmNpZGVudF9hY3Jlc19idXJuZWQpLAogIG1hcmtlciA9IGxpc3QoY29sb3IgPSAicmVkIiksCiAgbW9kZSA9ICJtYXJrZXJzIgopICU+JQogIGxheW91dCgKICAgIHRpdGxlID0gIkZpcmUgTG9jYXRpb25zIiwKICAgIG1hcGJveCA9IGxpc3QoCiAgICAgIHN0eWxlID0gImNhcnRvLXBvc2l0cm9uIiwKICAgICAgem9vbSA9IDUsICAjIEFkanVzdCB6b29tIGxldmVsCiAgICAgIGNlbnRlciA9IGxpc3QoCiAgICAgICAgbG9uID0gbWVhbihkYXRhJGluY2lkZW50X2xvbmdpdHVkZSwgbmEucm0gPSBUUlVFKSwKICAgICAgICBsYXQgPSBtZWFuKGRhdGEkaW5jaWRlbnRfbGF0aXR1ZGUsIG5hLnJtID0gVFJVRSkKICAgICAgKQogICAgKQogICkKCiMgU2hvdyB0aGUgcGxvdApmaWdfbG9jYXRpb24KYGBgCgojIyBXaWxkZmlyZSBBbmFseXNpcyBieSBXZWF0aGVyIEZhY3RvcnMKCmBgYHtyLCBmaWcud2lkdGg9MTJ9CiMgQ3JlYXRlIGluZGl2aWR1YWwgc2NhdHRlciBwbG90cwpwMSA8LSBnZ3Bsb3QoZGF0YSwgYWVzKHggPSBhdmdfd2luZHNwZWVkLCB5ID0gaW5jaWRlbnRfYWNyZXNfYnVybmVkKSkgK2dlb21fcG9pbnQoY29sb3IgPSAiYmx1ZSIpICt0aGVtZV9ncmV5KCkKCnAyIDwtIGdncGxvdChkYXRhLCBhZXMoeCA9IGF2Z190ZW1wLCB5ID0gaW5jaWRlbnRfYWNyZXNfYnVybmVkKSkgK2dlb21fcG9pbnQoY29sb3IgPSAicmVkIikgK3RoZW1lX2dyZXkoKQoKcDMgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0gYXZnX3ByZWNpcGl0YXRpb24sIHkgPSBpbmNpZGVudF9hY3Jlc19idXJuZWQpKSArZ2VvbV9wb2ludChjb2xvciA9ICJncmVlbjQiKSArdGhlbWVfZ3JleSgpCiMgQXJyYW5nZSBwbG90cyBpbiBhIHJvdyB3aXRoIGNvbnNpc3RlbnQgc2l6aW5nIGFuZCBzaGFyZWQgWSBheGlzCmZpZyA8LSBzdWJwbG90KHAxLCBwMiwgcDMsIG5yb3dzID0gMSwgc2hhcmVZID0gVFJVRSwgdGl0bGVYID0gVFJVRSwgdGl0bGVZID0gVFJVRSwgd2lkdGhzID0gYygwLjMzLCAwLjMzLCAwLjMzKSkgJT4lCiAgbGF5b3V0KAogICAgdGl0bGUgPSBsaXN0KAogICAgICB0ZXh0ID0gIldpbGRmaXJlIEFuYWx5c2lzIGJ5IFdlYXRoZXIgRmFjdG9ycyIsICAKICAgICAgeCA9IDAuNSwgICAgCiAgICAgIHhhbmNob3IgPSAiY2VudGVyIiwKICAgICAgZm9udCA9IGxpc3Qoc2l6ZSA9IDIwKSAgCiAgICApLAogICAgc2hvd2xlZ2VuZCA9IFRSVUUsCiAgICBtYXJnaW4gPSBsaXN0KGwgPSA1MCwgciA9IDUwLCBiID0gMTAwLCB0ID0gMTAwKSwKICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJBdmcgV2luZCBTcGVlZCIsIHplcm9saW5lID0gRkFMU0UpLAogICAgeGF4aXMyID0gbGlzdCh0aXRsZSA9ICJBdmcgVGVtcGVyYXR1cmUiLCB6ZXJvbGluZSA9IEZBTFNFKSwKICAgIHhheGlzMyA9IGxpc3QodGl0bGUgPSAiQXZnIFByZWNpcGl0YXRpb24iLCB6ZXJvbGluZSA9IEZBTFNFKSwKICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJBY3JlcyBCdXJuZWQiKQogICkKCmZpZwpgYGAKCiMjIENvcnJlbGF0aW9uIEhlYXQgTWFwCgo+IFRoZSBoZWF0bWFwIGlsbHVzdHJhdGVzIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHZhcmlvdXMgZmVhdHVyZXMgcmVsYXRlZCB0byB3aWxkZmlyZSBiZWhhdmlvciBhbmQgZW52aXJvbm1lbnRhbCBjb25kaXRpb25zLiBOb3RhYmx5LCBtaW5pbXVtIHRlbXBlcmF0dXJlIHNob3dzIGEgc3Ryb25nIHBvc2l0aXZlIGNvcnJlbGF0aW9uIHdpdGggbWF4aW11bSB0ZW1wZXJhdHVyZSAoMC44NCkgYW5kIGEgc3Ryb25nIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIHdpdGggZmlyZSBkdXJhdGlvbiAoLTAuNzgpLgoKYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0KIyBTZWxlY3Qgc3BlY2lmaWMgY29sdW1ucyBmcm9tIGRmMgpkZl9jb3IgPC0gZGF0YSAlPiUKICBzZWxlY3QoRmlyZV9EdXJhdGlvbiwgaW5jaWRlbnRfYWNyZXNfYnVybmVkLCBtaW5fdGVtcCwgbWF4X3RlbXAsIGF2Z190ZW1wLCBhdmdfd2luZHNwZWVkLAogICAgICAgICBhdmdfcHJlY2lwaXRhdGlvbiwgZWxldmF0aW9uLGFzcGVjdCwgc2xvcGUsIG5kdmksIGF2Z19wZHNpLCBhdmdfc3BpMzBkLCBuZG1pKQoKIyBDb21wdXRlIGNvcnJlbGF0aW9uIG1hdHJpeApjb3JfbWF0cml4IDwtIGNvcihkZl9jb3IsIHVzZSA9ICJjb21wbGV0ZS5vYnMiKQoKIyBQbG90IGNvcnJlbGF0aW9uIGhlYXRtYXAKZ2djb3JycGxvdChjb3JfbWF0cml4LCAKICAgICAgICAgICBtZXRob2QgPSAic3F1YXJlIiwgCiAgICAgICAgICAgdHlwZSA9ICJsb3dlciIsIAogICAgICAgICAgIGxhYiA9IFRSVUUsIAogICAgICAgICAgIGxhYl9zaXplID0gNSwgCiAgICAgICAgICAgY29sb3JzID0gYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSwKICAgICAgICAgICB0aXRsZSA9ICJGZWF0dXJlIENvcnJlbGF0aW9uIEhlYXRtYXAiKSArCiAgdGhlbWVfbGluZWRyYXcoKSsKICB0aGVtZSgKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMiwgYW5nbGUgPSA5MCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTIpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMjAsIGhqdXN0ID0gMC41KQogICkKYGBgCg==